﻿using Drive.AlertSystem;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading.Tasks;

namespace Drive.LiveExcelHost.Services
{
    public abstract class WebSocketHandler : IDisposable
    {
        public virtual void Dispose() { }
        protected Request request;
        protected WebSocketSession session;

        protected WebSocketHandler(Request request, WebSocketSession session)
        {
            this.request = request;
            this.session = session;
        }

        /// <summary>
        /// 收到消息报文
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        public abstract Task OnPacketReceived(string packet);



        /// <summary>
        /// 会话关闭
        /// </summary>
        /// <param name="closeStatus"></param>
        /// <returns></returns>
        public virtual Task OnClose(WebSocketCloseStatus? closeStatus)
        {
            return Task.CompletedTask;
        }
    }
    public abstract class SocketIOService : WebSocketHandler
    {
        protected SocketIOService(Request request, WebSocketSession session) : base(request, session)
        {
        }

        /// <summary>
        /// 收到消息报文
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        public override async Task OnPacketReceived(string packet)
        {

            var recvbody = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(packet);
            //发送消息 
            //消息格式为: command messageType [req_id] 消息体
            // messageType :::
            //connect	0	
            //disconnect	1	
            //event	2	未知
            //ack	3	
            //error	4	
            //binarevent	5	
            //binaryack	6

            var msg = recvbody[1];
            if (msg != "")
            {
                session.recentSendMessages.Add(new MessageForThrottle { SendTime = DateTime.Now, UserId = session.VisitorId });
                await this.OnMessageReceived(recvbody[0], recvbody[1]);
            }
        }

        /// <summary>
        /// 收到消息
        /// </summary>
        /// <param name="type"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public abstract Task OnMessageReceived(string type, string content);

        /// <summary>
        /// 会话建立完成
        /// </summary>
        /// <returns></returns>
        internal virtual Task OnSocketIoSessionCreate()
        {
            return Task.CompletedTask;
        }

        /// <summary>
        /// 会话销毁
        /// </summary>
        /// <returns></returns>
        internal virtual async Task OnSocketIoSessionDestory()
        {
            await Task.CompletedTask;
        }
        public virtual void ReportError(Exception ex)
        {
            var sid = this.request.Cookies.ContainsKey("sid") ? this.request.Cookies["sid"] : "";
            var builder = EventBuilder.Create("LiveHost", this.GetType().Name, ex.Message)
                        .SetBizPath(request.Method + " " + this.request.PathAndQuery)
                        .SetError(null, ex.StackTrace)
                        .SetLogLevel(NLog.LogLevel.Error)
                        .SetRequest(sid, string.Join("\r\n", this.request.Headers.Select(x => x.Key + ": " + x.Value)), this.request.Payload);

            NLog.LogManager.GetLogger(this.GetType().Name).Log(builder.Build());
        }

        /// <summary>
        /// socket.io , ping message from client
        /// </summary>
        /// <returns></returns>
        internal virtual Task OnSocketIoPingMessageReceived()
        {
            return this.ReplySocketIoPongMessage();
        }

        /// <summary>
        /// socket.io , replay a pong message to client
        /// </summary>
        /// <returns></returns>
        internal async Task ReplySocketIoPongMessage()
        {
            var toSend = TextUtil.TextToBytes("3");
            await session.WebSocket.SendAsync(toSend, WebSocketMessageType.Text, true, this.session.cancellationToken);
        }
    }
}
